package com.example.weixinsystem.config;

import com.example.weixinsystem.security.filter.JwtAuthenticationTokenFilter;
import com.example.weixinsystem.security.handler.AccessDeniedHandlerImpl;
import com.example.weixinsystem.security.handler.AuthenticationEntryPointImpl;
import com.example.weixinsystem.security.handler.LogoutSuccessHandlerImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

/**
 * @version 1.0.0
 * @className: SpringSecurity
 * @description: 配置类
 * @author: zhangjunfa
 * @date: 2023/5/27 15:23
 */
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true) //开启授权注解功能
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
    /**
     * token认证过滤器
     */
    private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;
    /**
     * 认证失败处理类
     */
    private AuthenticationEntryPointImpl authenticationEntryPoint;

    /**
     * 退出处理类
     */
    private LogoutSuccessHandlerImpl logoutSuccessHandler;
    /**
     * 授权的异常处理
     */
    private AccessDeniedHandlerImpl accessDeniedHandler;


    public SpringSecurityConfig(JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter,
                                AuthenticationEntryPointImpl authenticationEntryPoint,
                                LogoutSuccessHandlerImpl logoutSuccessHandler,
                                AccessDeniedHandlerImpl accessDeniedHandler) {
        this.jwtAuthenticationTokenFilter = jwtAuthenticationTokenFilter;
        this.authenticationEntryPoint = authenticationEntryPoint;
        this.logoutSuccessHandler = logoutSuccessHandler;
        this.accessDeniedHandler = accessDeniedHandler;
    }

    /**
     * 密码配置
     *
     * @return
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }


    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.
                //关闭csrf
                        csrf().disable()
                //不通过Session获取SecurityContext
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests()
                // 对于登录接口 允许匿名访问
                .antMatchers("/login").anonymous()
                // 静态资源放开
                .antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll()
                .antMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**").permitAll()
                // 除上面外的所有请求全部需要鉴权认证
                .anyRequest().authenticated();


        //添加Logout filter
        http.logout().logoutUrl("/logout").logoutSuccessHandler(logoutSuccessHandler);

        // 异常处理
        http.exceptionHandling()
                .authenticationEntryPoint(authenticationEntryPoint)
                .accessDeniedHandler(accessDeniedHandler);

        //把token校验过滤器添加到过滤器链中
        http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
    }

    /**
     * 此处需要注入一下。不然在 LoginService 中使用时会报错
     *
     * @return
     * @throws Exception
     */
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }


}
